#include "seq.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>

unsigned int testRead(int fd, unsigned int curr, unsigned int* resultsBuf, size_t bufSize, int mode) {
	int i, dq;
	assert(resultsBuf && bufSize);
	if (mode == ARITH_MODE) {
		dq = ioctl(fd, SEQ_GET_D);
	}
	else {
		dq = ioctl(fd, SEQ_GET_Q);
	}
	assert (dq>=0);
	assert(read(fd, resultsBuf, bufSize)>=0);
	for (i=0; i<bufSize; ++i) {
		if(curr != resultsBuf[i]) {
			printf("expected=%d\tgot from seq=%d\n",curr, resultsBuf[i]);
			assert(0);
		}
		if (mode == ARITH_MODE) {
			curr += dq;
		}
		else {
			curr *= dq;
		}
	}
	return curr;
}

void test1() {
	int f1;
	int numsToRead = 10;
	unsigned int *buf = malloc(numsToRead * sizeof(*buf));
	unsigned int curr = 6;
	int res;
	f1 = open ("/dev/seq0",O_RDWR);
	assert(0 == ioctl(f1, SEQ_CHG_MOD, ARITH_MODE));
	res = write(f1, &curr, sizeof(curr));
	if (res<0) {
		printf("error=%d\n", errno);
		assert(0);
	}
	curr = testRead(f1, curr, buf, numsToRead, ARITH_MODE);
	// finished part 1
	assert(0 == ioctl(f1, SEQ_SWCH_MOD));
	testRead(f1, curr, buf, numsToRead, GEOM_MODE);
	free(buf);
	close(f1);
}

void test2() {
	int f2;
	int numsToRead = 1;
	unsigned int *buf = malloc(numsToRead * sizeof(*buf));
	int i;
	unsigned int curr = 2;
	int res;
	f2 = open ("/dev/seq0",O_RDWR);
	assert(0 == ioctl(f2, SEQ_CHG_MOD, GEOM_MODE));
	res = write(f2, &curr, sizeof(curr));
	if (res<0) {
		printf("error=%d\n", errno);
		assert(0);
	}
	for (i=0 ;i<10; ++i) {
		if (i%2==0) {
			curr = testRead(f2, curr, buf, numsToRead, GEOM_MODE);
		}
		else {
			curr = testRead(f2, curr, buf, numsToRead, ARITH_MODE);
		}
		assert(0 == ioctl(f2, SEQ_SWCH_MOD));
	}
	curr = 1;
	assert(0 == ioctl(f2, SEQ_CHG_MOD, GEOM_MODE));
	assert(0 == ioctl(f2, SEQ_CHG_D, 4));
	assert(0 == ioctl(f2, SEQ_CHG_Q, 3));
	res = write(f2, &curr, sizeof(curr));
	if (res<0) {
		printf("error=%d\n", errno);
		assert(0);
	}
	for (i=0 ;i<10; ++i) {
		if (i%2==0) {
			curr = testRead(f2, curr, buf, numsToRead, GEOM_MODE);
		}
		else {
			curr = testRead(f2, curr, buf, numsToRead, ARITH_MODE);
		}
		assert(0 == ioctl(f2, SEQ_SWCH_MOD));
	}
	free(buf);
	close(f2);
}

void errorTest() {
	int f1, f2;
	unsigned int curr = 6;
	int res;
	f1 = open ("/dev/seq0",O_RDWR);
	f2 = open ("/dev/seq99",O_RDWR);
	assert(f2<0);
	assert(0 == ioctl(f1, SEQ_CHG_MOD, ARITH_MODE));
	assert(0 >  ioctl(f1, SEQ_CHG_MOD, (ARITH_MODE + GEOM_MODE + 1)));
	assert(0 >  ioctl(f1, SEQ_CHG_D, -4 ));
	assert(0 >  ioctl(f1, SEQ_CHG_D, 134 ));
	assert(0 >  ioctl(f1, SEQ_CHG_Q, -2 ));
	assert(0 >  ioctl(f1, SEQ_CHG_Q, 129 ));
	res = write(f1, &curr, 3);
	assert(res<0);
	close(f1);	
}

int main() {
	test1();
	printf("Test1 Passed!\n");
	test2();
	printf("Test2 Passed!\n");
	errorTest();
	printf("ErrorTest Passed!\n");
	printf("All Passed!\n");
	return 0;
}
